#include "mythread.h"
#include <QDebug>
#include <QLibrary>
#include <QFile>
#include "md5rc4.h"
#include "usermanage.h"


extern int ifDigitalVein;//指静脉id(0->未采集成功,>0->采集成功)
extern int ifDigitalVein2;//指静脉id(0->未采集成功,>0->采集成功)

mythread::mythread(QWidget *parent) : QThread(parent)
{
    openBox=0;
    QLibrary mylib("XGComApix64");

    if(mylib.load())
    {
        qDebug() << "dllhook加载成功";

    }
    else
    {
        qDebug() << "dllhook加载失败";
    }

    FV_SetDebug = (SetFV_SetDebug)mylib.resolve("FV_SetDebug");
    FV_ConnectDev = (SetFV_ConnectDev)mylib.resolve("FV_ConnectDev");
    FV_GetDevParam = (SetFV_GetDevParam)mylib.resolve("FV_GetDevParam");
    FV_HexToAscii = (SetFV_HexToAscii)mylib.resolve("FV_HexToAscii");
    FV_VerifyUser = (SetFV_VerifyUser)mylib.resolve("FV_VerifyUser");
    FV_CreateVeinLib = (SetFV_CreateVeinLib)mylib.resolve("FV_CreateVeinLib");
    FV_ImportVeinTemp = (SetFV_ImportVeinTemp)mylib.resolve("FV_ImportVeinTemp");
    FV_GetNullID = (SetFV_GetNullID)mylib.resolve("FV_GetNullID");
    FV_SearchUser = (SetFV_SearchUser)mylib.resolve("FV_SearchUser");
    FV_ExportVeinTemp = (SetFV_ExportVeinTemp)mylib.resolve("FV_ExportVeinTemp");
    FV_DestroyVeinLib = (SetFV_DestroyVeinLib)mylib.resolve("FV_DestroyVeinLib");
    FV_RecvCmdPacket = (SetFV_RecvCmdPacket)mylib.resolve("FV_RecvCmdPacket");
    FV_AsciiToHex = (SetFV_AsciiToHex)mylib.resolve("FV_AsciiToHex");
    FV_SendCmdPacket = (SetFV_SendCmdPacket)mylib.resolve("FV_SendCmdPacket");

    FV_WriteDevTemp = (SetFV_WriteDevTemp)mylib.resolve("FV_WriteDevTemp");
    FV_ReadDevTemp = (SetFV_ReadDevTemp)mylib.resolve("FV_ReadDevTemp");
    FV_WriteDevUserInfo = (SetFV_WriteDevUserInfo)mylib.resolve("FV_WriteDevUserInfo");
    FV_ReadDevUserInfo = (SetFV_ReadDevUserInfo)mylib.resolve("FV_ReadDevUserInfo");
    FV_DeleteDevTemp = (SetFV_DeleteDevTemp)mylib.resolve("FV_DeleteDevTemp");

    FV_SetDebug(1);//开启调试信息输出,不调用或参数为0则不输出调试信息

//    DevHandle = FV_ConnectDev((char*)"USB", NULL);//连接单个USB设备
    DevHandle = FV_ConnectDev("USB", "00000000"); //连接单个USB设备
    if(DevHandle > 0)
    {
        //连接成功
        char* p = NULL;
        char sParam[2000] = { 0 };
        FV_GetDevParam(DevHandle, sParam); //获取设备设置参数

        p = strstr(sParam, "MAXUSER:");
        if(p)
        {
            sscanf(p, "MAXUSER:%d", &MaxUser);
        }
        //qDebug() <<"222"<<p;
        qDebug()<<__LINE__<<sParam;

    }
    else
    {
        qDebug() <<"连接失败";
        return;
    }




}

void mythread::run()
{
    if(DevHandle <= 0)
    {
        DevHandle = FV_ConnectDev((char*)"USB", NULL);//连接单个USB设备
        if(DevHandle > 0)
        {
            //连接成功
            char* p = NULL;
            char sParam[2000] = { 0 };
            FV_GetDevParam(DevHandle, sParam); //获取设备设置参数

            p = strstr(sParam, "MAXUSER:");
            if(p)
            {
                sscanf(p, "MAXUSER:%d", &MaxUser);
            }
            //qDebug() <<"222"<<p;

        }
        else
        {
            emit sendThUserData(2,"连接指静脉设备失败");
            aps->hide();
            return;
        }

    }

    aps->show();
    int a=0;
    while(1)
    {
        if(openBox==0)
        {
            //指静脉解锁
            int ret=verification1_1(&a);
            if(ret==0)
            {
                //识别成功退出线程
                aps->hide();
                break;
            }
            else if(ret==-1)
            {
                aps->setLibel("识别失败,请重新识别");
                qDebug()<<"识别失败,请重新识别";
            }
        }
        else if(openBox==2)
        {
            //采集指静脉信息
            int NullId=getNullId();//获取空id
            qDebug()<<"NullId="<<NullId;

            int ret=DevAddUserProc(&NullId);
            if(ret==0)
            {
                //登记成功
                ifDigitalVein=NullId;
            }
            else
            {
                ifDigitalVein=0;
            }
//            usleep(600);
            aps->hide();
            break;
        }
        else if(openBox==3)
        {
            //采集指静脉信息
            int NullId=getNullId();//获取空id
            qDebug()<<"NullId="<<NullId;

            int ret=DevAddUserProc(&NullId);
            if(ret==0)
            {
                //登记成功
                ifDigitalVein2=NullId;
            }
            else
            {
                ifDigitalVein2=0;
            }
//            usleep(600);
            parent->hide();
            break;
        }
        else if(openBox == 4)
        {
            //1:1验证
            int ret=verification1_1(&digital_vein_device_id_);
            if(ret==0)
            {
                //识别成功退出线程
                emit sendThUserData(openBox,"1@#校验成功");
                aps->hide();
                break;
            }
            else if(ret==-1)
            {
                emit sendThUserData(openBox,"校验失败");
                qDebug()<<"识别失败,请重新识别";
                aps->hide();
                break;
            }

//            break;
        }

    }


}

int mythread::verification1_1(int *pParam)
{
    int ret = 0;
    unsigned char bData[16] = { 0 };
    char sData[50] = { 0 };
    int UserId = *(int*)pParam;//0为1：N, > 0为1:1
//    qDebug()<<"UserId="<<UserId;
    if(UserId > 0)
    {
        //指定用户ID验证，也就是1:1验证，否则就是1：N验证
        bData[0] = UserId&0xff;
        bData[1] = (UserId>>8)&0xff;
        bData[2] = (UserId>>16)&0xff;
        bData[3] = (UserId>>24)&0xff;
        bData[4] = 0; //分组组号
        FV_HexToAscii((char*)bData, 5, sData); //要转成字符串
    }

    qDebug()<<"27-请自然轻放手指.wav";
//    qDebug()<<"sData="<<sData;
    ret = FV_SendCmdPacket(DevHandle, XG_CMD_VERIFY, (char*)sData);
//    qDebug()<<"21212";
    if(ret == XG_ERR_SUCCESS)
    {
        for(;;)
        {
            ret = FV_RecvCmdPacket(DevHandle, sData, 6000); //默认设置手指检测超时是5秒，这里接收超时要大于设置的手指超时
            if(ret > 0)
            {
                FV_AsciiToHex(sData, (char*)bData);
                ret = bData[0];
                if(ret == XG_ERR_SUCCESS)
                {
                    char sMsg[255] = { 0 };
                    UserId = (bData[1] + (bData[2]<<8));
                    qDebug()<<"33-验证成功,UserId="<<UserId;
                    return 0;
                }
                else if(ret == XG_ERR_FAIL)
                {
                    if(bData[1] == 0x11)
                    {
                        qDebug()<<"采集特征失败,请正确放置手指";
                    }
                    qDebug()<<"验证失败";
                    return -1;
                }
                else if(ret == XG_INPUT_FINGER)
                {
                    //提示放手指
                    aps->setLibel("请自然轻放手指");
                    qDebug()<<"27-请自然轻放手指.wav";
                }
                else if(ret == XG_RELEASE_FINGER)
                {
                    //采集成功，提示可以拿开手指了
                    //在这里是不能给设备发指令播放语音的
                    qDebug()<<"采集成功，提示可以拿开手指了";
                }
                else
                {
                    qDebug()<<"未知错误";
                    break;
                }
            }
            else
            {
                qDebug()<<"收包失败";
                break;
            }
        }
    }
    else
    {
        qDebug()<<"发包失败";
    }
    return -2;
}

//判断指静脉设备是否连接成功
int mythread::ifDevHandle()
{
    if(DevHandle <= 0)
    {
        DevHandle = FV_ConnectDev((char*)"USB", NULL);//连接单个USB设备
        if(DevHandle > 0)
        {
            //连接成功
            char* p = NULL;
            char sParam[2000] = { 0 };
            FV_GetDevParam(DevHandle, sParam); //获取设备设置参数

            p = strstr(sParam, "MAXUSER:");
            if(p)
            {
                sscanf(p, "MAXUSER:%d", &MaxUser);
            }
        }
    }

    return DevHandle;
}

int mythread::isUid(int uid)
{
    //耗时太长
    QElapsedTimer t;
    t.start();
    int ret = 0;
    char *sTemp = (char *)malloc(20 * 1024);
    ret = FV_ReadDevTemp(DevHandle, uid, sTemp);
//    FV_RecvCmdPacket(DevHandle, sTemp, 1000);

    qDebug()<<__LINE__<<"获取指静脉信息：id="<<uid<<" ret="<<ret<<" info="<<sTemp;
    qDebug()<<__LINE__<<"所用时间："<<t.elapsed();
    free(sTemp);
    return ret;

//    return 1;
}

//获取空id
int mythread::getNullId()
{
    if(DevHandle == 0)
    {
        //"请先连接设备"
        return -1;
    }

//    char sData[50] = { 0 };
//    int ret = 0;

//    ret = FV_SendCmdPacket(DevHandle, XG_CMD_GET_EMPTY_ID, NULL);
//    if(ret == XG_ERR_SUCCESS)
//    {
//        //发包成功,准备收包
//        ret = FV_RecvCmdPacket(DevHandle, sData, 1000);
//        if(ret > 0)
//        {
//            //收包成功,解析包数据
//            FV_AsciiToHex(sData, sData);
//            ret = sData[0]; //0 指令返回正常，1指令执行有错误
//            if(ret != XG_ERR_SUCCESS) return sData[1]*-1;
//            return (sData[1] + (sData[2]<<8)); //返回获取的没有登记的ID
//        }
//    }
//    return ret*-1;


    qDebug()<<__LINE__<<"accuid="<<accountUid;

    int uid = -1;
    int i = 1;
    while(1)
    {
        int n = 0;

        for(int j=0;j<accountUid.size();j++)
        {
            if(accountUid.at(j).toInt() == i)
            {
                n = 1;
                break;
            }
        }

        if(n == 0)
        {
            uid = i;
            break;
        }

        i++;
    }

    int ret = isUid(uid);
    if(ret >= 0)
    {
        //用户本地已经存在，本地删除用户
        qDebug()<<__LINE__<<"uid本地已经存在，本地删除uid:"<<uid;
        DeletingUsersOne(uid);
    }
    return uid;
}

//采集指静脉信息
int mythread::DevAddUserProc(int *pParam)
{
    int ret = 0;
    unsigned char bData[16] = { 0 };
    char sData[50] = { 0 };
    int UserId = *(int*)pParam;

    bData[0] = UserId&0xff;
    bData[1] = (UserId>>8)&0xff;
    bData[2] = (UserId>>16)&0xff;
    bData[3] = (UserId>>24)&0xff;
    bData[4] = 0; //分组组号
    bData[5] = 3; //需要正确采集3次
    bData[10] = 10; //一共可以重试10次，在采集过程中有可能手指没放好导致采集失败则可以继续采集，直至成功了就了3次

    FV_HexToAscii((char*)bData, 16, sData); //要转成字符串
    ret = FV_SendCmdPacket(DevHandle, XG_CMD_ENROLL, (char*)sData);
    if(ret == XG_ERR_SUCCESS)
    {
        for(;;)
        {
            ret = FV_RecvCmdPacket(DevHandle, sData, 6000); //默认设置手指检测超时是5秒，这里接收超时要大于设置的手指超时
            if(ret > 0)
            {
                FV_AsciiToHex(sData, (char*)bData);
                ret = bData[0];
                if(ret == XG_ERR_SUCCESS)
                {
//                    aps->setLibel("登记成功");
                    emit sendThUserData(1,"1@#采集成功");
                    qDebug()<<"登记成功";
                    return 0;
                }
                else if(ret == XG_ERR_FAIL)
                {
                    int error = bData[1];
                    if(error == XG_ERR_INVALID_ID)
                    {
                        // UserId 错误，比如超过了最大用户数
//                        aps->setLibel("登记失败,ID非法");
                        emit sendThUserData(1,"登记失败,ID非法");
                        qDebug()<<"02-登记失败,ID非法";
                    }
                    if(error == XG_ERR_NOT_ENOUGH)
                    {
                        // 此ID不为NULL，此ID已经登记
//                        aps->setLibel("此ID已经登记");
                        emit sendThUserData(1,"采集失败，已有信息重复");
                        qDebug()<<"此ID已经登记";
                    }
                    if(error == XG_ERR_TIME_OUT)
                    {
                        // 手指检测超时，在超时时间内没有检测到手指
                        aps->setLibel("手指检测超时");
                        emit sendThUserData(1,"手指检测超时");
                        qDebug()<<"手指检测超时";
                    }
                    if(error == XG_ERR_DUPLICATION_ID)
                    {
                        // 检测到此手指已经注册，重复登记检查要设置为是才会检查是否重复登记
                        aps->setLibel("此手指已经登记");
                        emit sendThUserData(1,"此手指已经登记");
                        qDebug()<<"此手指已经登记";
                    }
                    if(error == XG_ERR_NO_SAME_FINGER)
                    {
                        // 检测到采集的特征不是同一个手指的，要把相同手指检测设置为是才会检查
                        aps->setLibel("不是同一个手指");
                        emit sendThUserData(1,"不是同一个手指");
                        qDebug()<<"不是同一个手指";
                    }
                    if(error == XG_ERR_NO_VEIN)
                    {
                        // 没有检测到有效的指静脉特征，一般是手指没有放好
                        aps->setLibel("采集指静脉失败");
                        emit sendThUserData(1,"采集指静脉失败");
                        qDebug()<<"采集指静脉失败";
                    }
                    return 1;
                }
                else if(ret == XG_INPUT_FINGER)
                {
                    //提示第一次放手指
                    if(bData[1] == 0)
                    {
                        //在这里是不能给设备发指令播放语音的
                        aps->setLibel("请自然轻放手指");
                        aps->setLibel2("(第一次采集)");
                        qDebug()<<"27-请自然轻放手指.wav";
                    }
                    else if(bData[1] == 1)
                    {
                        //在这里是不能给设备发指令播放语音的
                        aps->setLibel("请再放一次");
                        aps->setLibel2("(第二次采集)");
                        qDebug()<<"23-请再放一次.wav";
                    }
                    else if(bData[1] == 2)
                    {
                        //在这里是不能给设备发指令播放语音的
                        aps->setLibel("请再放一次");
                        aps->setLibel2("(第三次采集)");
                        qDebug()<<"23-请再放一次.wav";
                    }
                }
                else if(ret == XG_RELEASE_FINGER)
                {
                    //采集成功，提示可以拿开手指了
                    //在这里是不能给设备发指令播放语音的
                    aps->setLibel("请拿出手指，再次放入");
                    qDebug()<<"采集成功，可以拿开手指了";
                }
                else
                {
                    break;
                }
            }
            else
            {
                break;
            }
        }
    }

    return 2;
}
void mythread::getWindowPointer(QWidget *parent1)
{
    parent=parent1;
    aps=(AuthenticationPopups *)parent1;

}

void mythread::getWindowOpenBox(int ret)
{
    openBox=ret;
}

void mythread::getWindowOpenBox(int ret, int digital_vein_device_id)
{
    openBox=ret;
    digital_vein_device_id_ = digital_vein_device_id;
}

//通过id获取指静脉信息
int mythread::getDigitalInformation(int UserId,char *sUserInfo)
{
    memset(sUserInfo, 0, 10240);
    int ret = FV_ReadDevTemp(DevHandle, UserId,  sUserInfo);

    qDebug()<<__LINE__<<"获取指静脉信息：id="<<UserId<<" ret="<<ret<<" info="<<sUserInfo;
    //(0->成功,!0->失败)
    return ret;
}

//通过id设置初始信息
int mythread::getWriteDevInfo(int UserId, QString sUserInfo)
{
    char*  ch;
    QByteArray ba = sUserInfo.toLatin1();
    ch=ba.data();
    int ret = FV_WriteDevUserInfo(DevHandle, UserId, 1, ch);

    //(0->成功,!0->失败)
    return ret;
}

//删除一个用户
void mythread::DeletingUsersOne(int id)
{
    if(DevHandle <= 0)
    {
        qDebug()<<"请先连接设备";
        return;
    }
    FV_DeleteDevTemp(DevHandle, id);
}

//传入文件路径删除一个用户
void mythread::DeletingUsersOne(QString FilePath)
{
    if(DevHandle <= 0)
    {
        qDebug()<<"请先连接设备";
        return;
    }

    //创建QFile
    QFile myfile(FilePath);
    //打开文件
    bool ret=myfile.open(QIODevice::ReadOnly);
    if(!ret)
    {
        qDebug()<<"打开文件失败";
        return;
    }
    //读取一行指静脉sTemp数据
    QByteArray stb=myfile.readLine();
    stb=myfile.readLine();
    QString str=stb;
    QStringList buf=str.split("UID:");
    if(buf.size()<2)
    {
        qDebug()<<"指静脉文件错误";
        return;
    }
    int Uid=buf.at(1).toInt();

    DeletingUsersOne(Uid);

    myfile.close();
}
//更新一个用户
int mythread::setUserOne(QString FilePath)
{
    if(DevHandle <= 0)
    {
        qDebug()<<"请先连接设备";
        return -2;
    }

    Md5Rc4 *mr=new Md5Rc4();//初始化加解密对象

    //获取空id
//    int userId=getNullId();

    //创建QFile
    QFile myfile(FilePath);
    //打开文件
    bool ret=myfile.open(QIODevice::ReadOnly);
    if(!ret)
    {
        qDebug()<<"打开文件失败";
        delete mr;
        return -3;
    }
    //读取一行指静脉sTemp数据
    QByteArray stb=myfile.readLine();
    QByteArray st_buf=QByteArray::fromHex(stb);
    char* sTemp4 = st_buf.data();

    //把指静脉信息用rc4解密
    unsigned long len = st_buf.size();
    qDebug()<<"len="<<len;
    mr->rc4EncryptionDecode(sTemp4, len);
    QString array=QByteArray(sTemp4,len);

//        qDebug()<<"array="<<array;
    //读取一行指静脉sUser1Info数据
    QByteArray sui_buf=myfile.readLine();
    char* sUser1Info = sui_buf.data();

    QString str=sui_buf;//获取用户UID
    QStringList buf=str.split("UID:");
    if(buf.size()<2)
    {
        qDebug()<<"更新用户指静脉文件错误,需要删除重新下载"<<FilePath;
        delete mr;
        return -5;
    }
    int userId=buf.at(1).toInt();
//    int iret = isUid(userId);
//    if(iret >= 0)
//    {
//        //用户本地已经存在，本地删除用户
//        qDebug()<<__LINE__<<"uid本地已经存在，本地删除userId:"<<userId;
//        DeletingUsersOne(userId);
//    }

    //拼接两段数据用md5加密验证
    QString proclaimedWriting=QString("%1%2").arg(array).arg(sUser1Info);//拼接得到明文
    QStringList mylist=proclaimedWriting.split("\n");
    proclaimedWriting=mylist.at(0);

    QString md5=mr->md5Encryption(proclaimedWriting);//得到密文

    //读取一行指静脉sUser1Info数据
    QByteArray md5_buf=myfile.readLine();
    if(md5!=md5_buf)
    {
        qDebug()<<__LINE__<<"指静脉文件密文不一致,需要删除重新下载"<<FilePath;
        delete mr;
        return -1;
    }
    QByteArray ba = array.toUtf8();
    char *ch=ba.data();

//    qDebug()<<__LINE__<<ch;

    int ret2 = FV_WriteDevTemp(DevHandle, userId, ch, sUser1Info);
    if(ret2 == 0)
    {
        qDebug()<<"写入模板成功 用户  "<<userId;
    }
    else
    {
        qDebug()<<"写入模板失败 用户  "<<userId;
        delete mr;

        return -1;
    }

    delete mr;
    return userId;
}
